const path = require('path')
const fs = require('fs')
const { htmlEncodeByRegExp, errorLog } = require('../util')
const CompInfoUtil = require('./CompInfoUtil')

/**
 * vue 组件生成md文档
 * @class RenderMd
 */
class RenderMd {
  /**
   * 输出.vue文件渲染的md文本
   * @param {*} filePath .vue文件
   * @param {*} vueDoc vueDoc配置项
   * @return {Promise<string>}
   * @memberof RenderMd
   */
  static render(filePath, vueDoc) {
    // let vueDoc = {
    //   autoOutput: {
    //     title: true,
    //     props: true,
    //     slot: true,
    //     method: true,
    //     event: true
    //   }
    // }
    let autoOutput = vueDoc['autoOutput'] || {}
    let isOutputProps = autoOutput['props']
    let isOutputSlot = autoOutput['slot']
    let isOutputMethod = autoOutput['method']
    let isOutputEvent = autoOutput['event']
    let isOutputTitle = autoOutput['title']
    return new Promise((resolve) => {
      CompInfoUtil.getInfo(filePath).then((componentInfo) => {
        let strList = []

        let compName = componentInfo['compName']
        let compDes = componentInfo['compDes']

        // md文件头部
        let mdTitle = `---\ntitle: ${compName}\n---\n`

        // 描述
        let nameAndDes = (isOutputTitle && RenderMd.getNameAndDes(compName, compDes)) || ''

        let title = (isOutputTitle && `${mdTitle}\n${nameAndDes}\n`) || ''
        title && strList.push(title)

        // demo说明
        let docsBlocksStr = RenderMd.getDemo(filePath, componentInfo['docsBlocks']) || ''
        docsBlocksStr && strList.push(docsBlocksStr)

        let propsStr = (isOutputProps && RenderMd.getProps(componentInfo['propsList'])) || ''
        propsStr && strList.push(propsStr)

        let slotStr = (isOutputSlot && RenderMd.getSlot(componentInfo['slotsList'])) || ''
        slotStr && strList.push(slotStr)

        let methodStr = (isOutputMethod && RenderMd.getMethods(componentInfo['methodsList'])) || ''
        methodStr && strList.push(methodStr)

        let eventStr = (isOutputEvent && RenderMd.getEvent(componentInfo['eventList'])) || ''
        eventStr && strList.push(eventStr)

        let mdData = ''
        if (strList.length > 0) {
          mdData = strList.join('\n---\n')
        }
        resolve(mdData)
      })
    })
  }

  /**
   * 组件的名称和描述
   * @static
   * @param {*} name
   * @param {*} desc
   * @return {*}
   * @memberof RenderMd
   */
  static getNameAndDes(name, desc) {
    let str = ''
    if (name) {
      str += `## ${name}\n`
    }
    if (name) {
      str += `- 详情：${desc}\n`
    }
    return str
  }

  /**
   * 演示例子文本
   * @static
   * @param {string} fromPath
   * @param {array} docsBlocks
   * @return {*}
   * @memberof RenderMd
   */
  static getDemo(fromPath, docsBlocks) {
    if (!docsBlocks) {
      return ''
    }
    let dirPath = path.resolve(fromPath, '..')
    let demoFilePathArr = []
    let demoStr = ''

    for (const docs of docsBlocks) {
      let demoArr = docs.match(/<demo>(.*)<\/demo>/g)
      if (demoArr) {
        for (let demoFile of demoArr) {
          demoFile = String(demoFile)
            .trim()
            .replace(/<(\/?\\?)demo>/g, '')
          if (demoFile) {
            if (!path.isAbsolute(demoFile)) {
              demoFile = path.resolve(dirPath, demoFile)
            }
            try {
              fs.accessSync(demoFile)
              demoFilePathArr.push(demoFile)
              demoStr += fs.readFileSync(demoFile).toString() + '\n'
            } catch (error) {
              errorLog('文件不存在', demoFile)
            }
          }
        }
      }
    }
    return demoStr
  }

  /**
   * 属性列表渲染md文本
   * @param {*} propsList
   * @return {*}
   * @memberof RenderMd
   */
  static getProps(propsList) {
    if (!propsList) {
      return ''
    }
    // ### Attributes
    // | 参数      | 说明          | 类型      | 可选值                           | 默认值  |
    // |---------- |-------------- |---------- |--------------------------------  |-------- |
    // | title     | 标题           | string | — | — |
    // | type | 主题 | string | success/warning/info/error | info |
    // | description | 辅助性文字。也可通过默认 slot 传入 | string | — | — |
    // | closable | 是否可关闭 | boolean | — | true |
    // | center | 文字是否居中 | boolean | — | true |
    // | close-text | 关闭按钮自定义文本 | string | — | — |
    // | show-icon | 是否显示图标 | boolean | — | false |
    // | effect | 选择提供的主题 | string | light/dark | light |
    let title = `## 属性\n`
    let headDes = `\n| 参数 | 类型 | 默认值 | 可选值 | 描述 |\n`
    let tabelHead = `| --- | --- | --- | --- | --- |\n`
    let tabelStr = ''
    for (const props of propsList) {
      // 参数名
      let name = props['name'] || ''

      // 可选值

      let optionalStr = (props['values'] && props['values'].join('、')) || '-'

      // 类型
      let type = (props['type'] && props['type']['name']) || ''

      // 默认值
      let defaultValue = (props['defaultValue'] && props['defaultValue']['value']) || ''
      let isFunc = (props['defaultValue'] && props['defaultValue']['func']) || false
      if (isFunc) {
        defaultValue = '<code>function</code>'
      }

      // 描述
      let desc = props['description'] || ''
      tabelStr += `|${name} |${type} |${defaultValue} |${optionalStr}| ${desc}|\n`
    }
    let str = `${title}${headDes}${tabelHead}${tabelStr}`
    return str
  }

  /**
   * 获取Slot渲染md文本
   * @param {*} slotList
   * @return {*}
   * @memberof RenderMd
   */
  static getSlot(slotList) {
    if (!slotList) {
      return ''
    }
    // | Name | Description |
    // |------|--------|
    // | — | 描述 |
    // | title | 标题的内容 |
    let title = `## Slot\n`
    let headDes = `\n| 名称 | 描述 |\n`
    let tabelHead = `| --- | --- |\n`
    let tabelStr = ''
    for (const slot of slotList) {
      // 参数名
      let name = slot['name'] || ''

      // 描述
      let desc = slot['description'] || ''
      tabelStr += `|${name}|${desc}|`
    }
    let str = tabelStr && `${title}${headDes}${tabelHead}${tabelStr}`
    return str
  }

  /**
   * 事件渲染md文本
   * @param {*} eventList
   * @return {*}
   * @memberof RenderMd
   */
  static getEvent(eventList) {
    if (!eventList) {
      return ''
    }
    // ### Events
    // | 事件名称 | 说明 | 回调参数 |
    // |---------- |-------- |---------- |
    // | close | 关闭alert时触发的事件 | — |
    let str = ''
    let title = `## 事件\n`
    let headDes = `\n| 名称 | 描述 | 回调参数 |\n`
    let tabelHead = `| --- |--- | --- |\n`
    let tabelStr = ''
    for (const event of eventList) {
      // console.log('事件：', event)
      // 名称
      let name = event['name'] || ''
      // 描述
      let desc = event['description'] || ''
      // 回调参数
      let properties = RenderMd.getEventParams(event['properties']) || ''
      tabelStr += `|${name}|${desc}|${properties}|\n`
    }
    str = tabelStr && `${title}${headDes}${tabelHead}${tabelStr}`
    return str
  }

  /**
   * 事件参数渲染md文本
   * @param {*} eventProperties
   * @return {*}
   * @memberof RenderMd
   */
  static getEventParams(eventProperties) {
    let str = ''
    if (eventProperties) {
      for (const propertie of eventProperties) {
        let type = (propertie['type'] && propertie['type']['names'] && propertie['type']['names'][0]) || ''
        // console.log('getEventParams：', propertie['type'])
        let name = propertie['name'] || ''
        let desc = propertie['description'] || ''
        str += `<code>${name}</code>：<code>${type}</code> ${desc}; `
      }
    }
    return str
  }

  /**
   * 函数详情渲染md文本
   * @param {*} des
   * @return {*}
   * @memberof MdRender
   */
  static getMethodDes(des) {
    if (des) {
      return `- 详情： ${des}`
    }
    return ''
  }

  /**
   * 函数名渲染md文本
   * @param {*} name
   * @return {*}
   * @memberof MdRender
   */
  static getMethodName(name) {
    if (name) {
      return `### ${name}`
    }
    return ''
  }

  /**
   * 函数返回参数渲染md文本
   * @param {*} returns
   * @return {*}
   * @memberof MdRender
   */
  static getMethodReturn(returns) {
    if (!returns) {
      return ''
    }
    let str = ''
    // [{"type":{"names":["array","undefined"]},"description":"返回列表"}]
    for (const key in returns) {
      let item = returns[key]
      let typeList = item['type']
      // 描述
      let desc = item['description']
      let nameArr = []
      if (typeList) {
        // 类型字符
        for (const typeName in typeList) {
          nameArr.push(`<code>${htmlEncodeByRegExp(typeList[typeName])}</code>`)
        }
        let typeStr = nameArr.join('|')

        desc = (desc && `- ${desc}`) || ''

        str = `\n- 返回：${typeStr}${desc}`
        return str
      }
    }
    return str
  }

  /**
   * 函数参数渲染md文本
   * @param {*} params
   * @return {*}
   * @memberof MdRender
   */
  static getMethodParams(params) {
    if (params && params.length) {
      let headDes = `\n| 参数 | 类型 | 默认值 | 描述 |`
      let tabelHead = `| --- | --- | --- | --- |`
      let tabelItemArr = [headDes, tabelHead]
      for (const param of params) {
        let name = param['name'] || ''
        let type = param['type']

        // 默认值
        let defaultvalue = param['defaultvalue']
        let defaultvalueStr = ' '

        // 参数名
        let nameStr = name
        if (defaultvalue) {
          nameStr = `[${name}]`
          defaultvalueStr = defaultvalue
          defaultvalueStr = `<code>${htmlEncodeByRegExp(defaultvalueStr)}</code>`
        }

        // 参数类型
        let paramTypeStr = ' '
        if (type) {
          let names = type['name']
          paramTypeStr = `<code>${htmlEncodeByRegExp(names)}</code>`
        }

        // 参数描述
        let description = param['description']
        let descriptionStr = ' '
        if (description) {
          descriptionStr = description
        }
        let item = `| ${nameStr} | ${paramTypeStr} | ${defaultvalueStr} | ${descriptionStr} |`
        tabelItemArr.push(item)
      }
      let paramsMdStr = tabelItemArr.join('\n')
      return paramsMdStr
    }
    return ''
  }

  /**
   * 函数渲染md文本
   * @param {*} methodsList
   * @return {*}
   * @memberof RenderMd
   */
  static getMethods(methodsList) {
    let str = ''
    if (methodsList) {
      let title = '## 方法'
      let methodStr = ''
      for (const methods of methodsList) {
        let nameStr = RenderMd.getMethodName(methods['name'])
        if (nameStr) {
          let desStr = RenderMd.getMethodDes(methods['description']) || ''

          let paramsStr = RenderMd.getMethodParams(methods['params']) || ''

          let returnsStr = RenderMd.getMethodReturn(methods['returns']) || ''
          methodStr += `${nameStr}\n${desStr}\n${paramsStr}\n${returnsStr}\n`
        }
      }
      str = methodStr && `${title}\n${methodStr}`
    }
    return str
  }
}

module.exports = RenderMd
